Le langage de programmation Go suit son chemin. Voici quelques faits marquants depuis la précédente dépêche sur LinuxFr.org :
- Le site officiel, golang.org a été refait : il est plus complet et la navigation est plus simple.
- La prise en charge de Go dans GCC a été commitée et sera donc incluse dans la prochaine version de GCC, la 4.6.
- Tous les tests sont maintenant au vert pour l'architecture ARM et le portage vers Windows avance
- La spécification du langage évolue : arrivée de recover, nouvelle syntaxe pour les fonctions avec un nombre variable d'arguments, simplification de la syntaxe pour les types composites, etc.
- De nouvelles commandes sont disponibles, dont goinstall, un gestionnaire de paquets qui peut, entre autres, installer des paquets depuis GitHub, Bitbucket, Launchpad et Google code et goplay qui permet de tester Go depuis un navigateur web.
- Rob Pike a fait une présentation très intéressante : The Expressiveness Of Go (PDF).
Aller plus loin
# goland
Posté par maggic . Évalué à 3.
[^] # Re: goland
Posté par Sylvain D. . Évalué à 1.
[^] # Re: goland
Posté par nonas . Évalué à 0.
[^] # Re: goland
Posté par Dup (site web personnel) . Évalué à 10.
[^] # Re: goland
Posté par niconoe . Évalué à 6.
# Mais sinon, pourquoi je devrais m'intéresser à ce énième langage ?
Posté par Johands . Évalué à 10.
Pourquoi Go ?
Pour obtenir un langage à la fois simple et performant. Arguments de poids pour toute personne ayant tenté d'utiliser du C++ ou de faire du calcul numérique sous Python.
Structures, Méthodes et Interfaces
Pour faire bref, l'équipe de Go a redécouvert le principe de simplicité des langages fonctionnels : définir des données simples et concentrer la complexité dans un ensemble de fonctions servant à modifier ces briques d'octets.
Visibilité (public/privé)
Aïe, différencier les membres publiques des privés par leur casse ! Ça pique aux yeux mais l'idée se tient. Après les goûts et les couleurs …
Je m'étonne juste de l'argument "il est facile de repérer la présence ou non d'une majuscule, donc le code est plus simple à comprendre" après 3 diapos nous expliquant qu'en fait les interfaces on ne les déclare pas explicitement, si le développeur veut savoir quel type d'argument est accepté par ce bout de fonction, il n'a qu'à parcourir lui-même le code et vérifier que son objet implémente les-dites méthodes. Sur le coup, j'ai du mal à digérer l'argument de simplicité.
Coroutines, fermetures, spaghettis stacks et autres joies de la programmation concurrente
En fait Go n'est qu'une ré-écriture de Common Lisp maquillée avec une syntaxe à-la Algol, reprenant les concepts phares de CLOS, le tout agrémenté de pointeurs et muni d'une solide gestion des threads !
… intéressant tout cela, intéressant … je m'en vais finir la lecture de Practical Common Lisp pour l'occasion ,-)
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Bruno Michel (site web personnel) . Évalué à 2.
Sinon, je n'ai pas fait de LISP depuis un bout de temps, mais il me semblait qu'il n'y avait rien dans Common Lisp pour gérer la programmation concurrente. Je me trompe ?
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par lasher . Évalué à 6.
Oui enfin, une co-routine c'est justement un thread léger, généralement impossible à préempter à moins d'une exception ou que la coroutine elle-même décide de le demander... Ça me semble 'achement proche des Goroutines. :)
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Bruno Michel (site web personnel) . Évalué à 4.
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par lasher . Évalué à 3.
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Johands . Évalué à 2.
Arf bien vu. Même si pour ma défense, et comme lasher le fait remarquer, il y a possibilité de simuler partiellement l'un à l'aide du second, et vice-versa.
mais il me semblait qu'il n'y avait rien dans Common Lisp pour gérer la programmation concurrente.
D'après le peu que j'ai lu sur Common Lisp, c'est effectivement son gros défaut. Je ne trouve aucune référence à cette question dans les hyperspecs et il semblerait que chaque interpréteur (sbcl, clisp) ait décidé de créer sa propre API. Si quelqu'un de mieux informé pouvait développer.
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par hocwp (site web personnel) . Évalué à 1.
Par contre il existe des fines couches pour standardiser l'API à travers toutes les implémentations.
Une des plus utilisée étant les bordaux-threads : http://common-lisp.net/project/bordeaux-threads/
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Thomas . Évalué à 1.
http://www.pvk.ca/Blog/Lisp/concurrency_with_mvars.html
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Krunch (site web personnel) . Évalué à 3.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par lasher . Évalué à 4.
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Victor . Évalué à 3.
Ils ont éventuellement innové avec leur interfaces, mais perso je trouve ça super nul, ça aide pas du tout à bien structurer son code, et c'est super pas utile en terme d’interopérabilité pour quand on fait des libs et qu'on veut avoir des types qui sont compris de la même façon par tout le monde.
La notion d'interface permet de donner une sémantique à ses méthode, et là, justement ce n'est que du structural typing statiquement typé !
En fait, je vais comme à chaque fois revenir à ce que j'aime, mais je trouve qu'un langage comme Scala innove bien plus.
Entre autres avec ses mixins, avec son typage VRAIMENT avancé (higher-kind et autres trucs du genre), avec une vraie réflexion sur le lien entre objets et fonctions.
Et il a même du structural typing... !
On est capable d'y retrouver tout ce qu'on connaissait du monde plus formel des langages fonctionnels, et de tout les délires venant de la théorie des catégories, ce qui permet de fabriquer des abstractions vérifiables (par exemple voir tout le travail sur la concurrence avec des librairies pour le pi-calculus, pour les acteurs, et le tout SANS primitives intégrées au langage contrairement à ce que déclare la présentation de Go comme étant obligatoire pour faire de la concurrence : c'est justement rendu possible par cet objet-fonctionnel).
Enfin bon, Go c'est vachement bien, ça doit bien marcher, être optimisé, mais est-ce que ça va rendre le monde de la programmation et de l’ingénierie du logiciel meilleur ? Je ne pense pas !
Scala ? Oui je le pense : avec de tels langages on développe de nouvelles manière d'aborder les problèmes (voir tout le travail sur les contraintes sémantiques encodées avec les types pour avoir plus de vérification et de sûreté à la compilation par exemple).
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par lolop (site web personnel) . Évalué à 2.
(vraie question vs l'utilisation de la jvm derrière)
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Victor . Évalué à 4.
Mais je ne suis pas du tout un expert sur la question :>
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Victor . Évalué à 2.
http://infoscience.epfl.ch/record/150346
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par collinm (site web personnel) . Évalué à 1.
www.solutions-norenda.com
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Ontologia (site web personnel) . Évalué à 2.
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Moonz . Évalué à 1.
Je crois que tu n’as pas compris leur système d’interfaces. Une même interface est comprise pareille pour tout le monde. Si tu fais un minimum de Go, tu verras par exemple que l’interface Reader est utilisée absolument partout (dans io, http, json, logger,…), et tout le monde la comprend pareil. Idem pour l’interface Error.
> La notion d'interface permet de donner une sémantique à ses méthode
Ben oui, c’est ce que fait une interface en Go ; un ReadWriter, c’est un objet sur lequel on peut lire et écrire.
Ou alors j’ai pas compris ce que tu voulais dire par « donner une sémantique à ses méthodes ».
> et là, justement ce n'est que du structural typing statiquement typé !
En quoi est-ce supposé être en contradiction ?
> avec son typage VRAIMENT avancé (higher-kind et autres trucs du genre)
Par exemple ?
> avec une vraie réflexion sur le lien entre objets et fonctions
Par exemple ?
> (voir tout le travail sur les contraintes sémantiques encodées avec les types pour avoir plus de vérification et de sûreté à la compilation par exemple).
Un lien ?
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Victor . Évalué à 6.
Je crois que tu n’as pas compris leur système d’interfaces. Une même interface est comprise pareille pour tout le monde. Si tu fais un minimum de Go, tu verras par exemple que l’interface Reader est utilisée absolument partout (dans io, http, json, logger,…), et tout le monde la comprend pareil. Idem pour l’interface Error.
Ben oui, c’est ce que fait une interface en Go ; un ReadWriter, c’est un objet sur lequel on peut lire et écrire.
Ou alors j’ai pas compris ce que tu voulais dire par « donner une sémantique à ses méthodes ».
Oui, je n'ai pas été très clair (et un truc m'échappe peut-être), mais en gros, comme ton interface est inférée implicitement, si tout le monde fait bien attention, alors ça va aller, mais imagine qu'une personne implémente un read et un write qui ne sont pas compatible (pour une raison qui m'échappe :) alors est-ce que cette chose implémente ReadWriter ou juste Reader et Writer ?
Ce qui m'embête c'est cet implicite qui ne rend pas les choses explicites : quand je dis que j'implémente ReaderWriter, je signe un contrat pour une sémantique particulière, et peut-être qu'il y a plusieurs ReaderWriter, selon la sémantique.
Quand j'implémente une méthode read, j'implémente une méthode read et je met la signification que je veux derrière.
Sinon, avec des interfaces moins utilisées, des signification différentes vont émerger dans différentes parties du monde et un jour un mec va dire : ah zut, on a pas pareil, il faut se sync ! Ah oui mais merde, on est incapable de savoir à quelle sémantique ce rapporte cette implémentation ou celle-ci. Avec des interfaces, on a juste à regarder de quelle interface on parle (sans oublier qu'il y a un namespace qui permet de différencier les interfaces avec le même nom et ce, par le compilateur, pas un humain !).
> et là, justement ce n'est que du structural typing statiquement typé !
En quoi est-ce supposé être en contradiction ?
Le fait que le lien méthode / interface est implicite avec le structural typing.
Dans Go, l'interface ne sert que à donner des jolis noms à une définition structurelle d'un type, avec des interfaces à la Java, c'est plus qu'un nom, c'est un contrat à signer par ses implémenteurs.
Et si tu manques de flexibilité et d'ouverture, il existe d'autres solutions qui s'inspire des type classes :
http://ropas.snu.ac.kr/~bruno/papers/TypeClasses.pdf
Sur le typage avancé :
Pour le concept : http://www.cs.kuleuven.be/~adriaan/files/genericshk/tcpoly-o(...)
Pour son utilisation :
http://drops.dagstuhl.de/opus/volltexte/2009/2338/
http://www.comlab.ox.ac.uk//files/2187/ModularVisitor.pdf
Pour la réflexion object / fonctionnel :
http://infoscience.epfl.ch/getfile.py?docid=13847&name=T(...)
Mais bon, ensuite il faut fouiller le web, il y a des millions de trucs passionnants :
http://www.scala-lang.org/node/143
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Johands . Évalué à 5.
Au départ je me suis dit la même chose : encore un langage qui ré-invente lisp. Mais Go comble une niche : un langage système type C avec plus de flexibilité (interfaces, fermetures, etc.) et un solide support des threads. Et dans ce domaine, j'ai vraiment du mal à lui trouver un concurrent.
Ils ont éventuellement innové avec leur interfaces, mais perso je trouve ça super nul, ça aide pas du tout à bien structurer son code, et c'est super pas utile en terme d’interopérabilité …
Petite nuance sur ce point : je préfère personnellement l'approche suivie par Go, qui est la même qu'en Common Lisp avec ses fonctions génériques ou en Haskell avec ses type-classes.
L'idée est d'abordée l'écriture d'un programme de façon analogue à un théorème en mathématiques. Par exemple, "étant donné x réel et n un entier, on définit x à la puissance n par …" se traduit simplement en Go/CLisp/Haskell par "étant donné deux objets, le premier ayant une interface type Real et le second type Integer, alors on peut écrire notre fonction power ainsi ...".
On se concentre sur les propriétés des objets, et non sur leur identité.
C'est aussi plus facile d'étendre ces propriétés, il suffit juste d'écrire les méthodes requises par l'interface, plus la peine de perdre son temps à hériter, surcharger ceci et protéger cela.
Non, le truc qui me chagrine, c'est le côté "implicite" des interfaces dans Go.
Quant à Scala, c'est une autre histoire qui m'est malheureusement inconnue.
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Gniarf . Évalué à 0.
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Victor . Évalué à 3.
Ce que je voulais mettre en avant c'est qu'il y a différentes utilisation des interfaces, et que Go n'en permet qu'une seule, qui bien que flexible, n'est pas la plus importante à mes yeux dans un monde on ton code a de grandes chance de se retrouver dans les mains d'un autre.
Sinon, oui pour le langage de niche, mais c'est pour ça que je dis que c'est un n-ieme spinoff et qu'il n'innove pas.
En revanche il répond à un besoin très clair, et je ne le nie pas !
J'ai toujours tendance à m'exciter quand je commence à parler de Scala et parfois je peux paraître dédaigneux… Je m'en excuse !
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par HardShooter . Évalué à 5.
class Duck {
def quack = println("Quaaaaaack !")
def feathers = println("The duck has white and gray feathers.")
}
class Person {
def quack = println("The person imitates a duck.")
def feathers = println("The person takes a feather from the ground and shows it.")
}
def inTheForest(duck: { def quack; def feathers }) = {
duck.quack
duck.feathers
}
Des interfaces implicites comme go :
type Duck = { def quack; def feathers }
def inTheForest(duck: Duck) = {
duck.quack
duck.feathers
}
Ou des traits explicites (equivalent du duo interface/classe abstraite de Java)
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par reno . Évalué à 5.
Ahem, tu oublie "juste" le typage statique..
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Johands . Évalué à 3.
Arf oui, j'ai un peu forcé le trait :o
D'ailleurs il existe bien d'autres différences entre ces deux langages. Mais les concepts ré-empruntés par Go font plaisir à voir (enfin des fermetures !).
[^] # Re: Mais sinon, pourquoi je devrais m'intéresser à ce énième langage
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 2.
Ça veut dire que moins de programmes valides qu'on écrit en CL seront acceptés par Go, c'est tout !
Puis coller un typeur à CL (ou un sous-ensemble) c'est pas dur…
Tant qu'à faire, si je devais coder en Go, je programmerais sans doute en CL, pour compiler vers Go après au début, jusqu'à ce que les gens autour se rendent compte qu'il n'est en fait pas nécessaire d'utiliser Go…
# typage mou
Posté par satantango . Évalué à 6.
Donc, longue vie aux bugs.
Mais pourquoi réinventer la roue, elle s'appelle ADA, il faudrait juste
lui rajouter des enjoliveurs.
[^] # Re: typage mou
Posté par Moonz . Évalué à 7.
Qu’est-ce que tu entends par là ?
C’est du typage statique, fort, à inférence locale. Je vois pas ce qu’il te faut de plus. C’est l’inférence locale qui te gène ? Pourquoi ?
[^] # Re: typage mou
Posté par Bruno Michel (site web personnel) . Évalué à 7.
Sinon, je tombe fréquemment sur l'argument "pas de typage fort => plein de bugs". Est-ce qu'il y a des études sérieuses qui montrent ce effet de cause à effet ?
Je connais des études qui montrent que le nombre de bugs est très fortement lié au nombre de lignes de code et d'autres qui montrent que l'écriture de tests permettent de réduire fortement le nombre de bugs, mais je n'ai pas trop creusé la question du typage statique fort. Est-ce qu'un lecteur de linuxFr.org aurait un lien vers une ou plusieurs études à ce sujet ?
[^] # Re: typage mou
Posté par lasher . Évalué à 6.
Le typage fort ne fait pas tout bien sûr, mais il assure presque à tous les coups que ton programme se terminera en cas de bug lié aux types. Je ne compte plus le nombre de fois où j'ai expliqué à des étudiants à quel point ils étaient chanceux d'avoir un bug reproductible en C (que j'adore par ailleurs)... :-)
[^] # Re: typage mou
Posté par dest . Évalué à 4.
[^] # Re: typage mou
Posté par daimrod . Évalué à 4.
[^] # Re: typage mou
Posté par khivapia . Évalué à 4.
C'est quoi la différence entre les deux, fondamentalement ?
Merci,
[^] # Re: typage mou
Posté par daimrod . Évalué à 3.
l'impératif « naturellement » en OCaml) et je ne suis pas sûr qu'il ai les classes de types.
[^] # Re: typage mou
Posté par Obi MO (site web personnel) . Évalué à 3.
Ceci y ressemble pourtant:
http://caml.inria.fr/pub/docs/manual-ocaml/libref/Lazy.html
Certes, c'est dans la lib standard et pas dans le langage.
Pour les classes de types, je ne connais pas assez bien les aspects objet pour te répondre, je ne m'en sers que quand cela m'est vraiment utile. Ça m'est arrivé une fois, pour des raisons de compatibilité avec une API objet.
[^] # Re: typage mou
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 4.
let concatMap f x = List.fold_left (@) [] (List.map f x);;
let return x = [x];;
let (>>=) v f = concatMap f v;;
let (>>) v f = let _ = concatMap f v in [];;
let test () =
[0;1;2;3;4;5] >>=
(fun x -> ["A";"B";"C";"D";"E"] >>=
(fun y -> return (x,y)));;
Et voila le travail.
Les monades, quand on code, c'est rien d'autre qu'une interface…
Et vu qu'OCaml a une couche objet, j'imagine qu'on peut même coder ça proprement, avec l'inférence de type qui se charge d'appeler les méthodes ">>=", ">>" et "return" correspondant à l'usage précis dans le code.
[^] # Re: typage mou
Posté par daimrod . Évalué à 3.
[^] # Re: typage mou
Posté par Ontologia (site web personnel) . Évalué à 3.
let concatMap f x = List.fold_left (@)
C'est quoi le @ ?return n'est pas un mot clé ?
let (>>) v f = let _ = concatMap f v in [];;
pourquoi le let _ ? ça fait quoilet test () =
je comprend pas ce que ça signifie, syntaxiquement, sémantiquement...« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: typage mou
Posté par lasher . Évalué à 2.
[^] # Re: typage mou
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 5.
[1;2]@[3;4];; (* [1;2;3;4] *)
return n'est pas un mot clé. Dans la mesure où le langage est fonctionnel et où toute expression et tout statement retourne une valeur, ça serait inutile d'avoir ce mot clef [http://caml.inria.fr/pub/docs/manual-ocaml/manual044.html]
En haskell non plus ce n'est pas un mot clef.
let _ = foo
ça évalue foo puis ça jette le résultat. _ est un nom de variable valide, mais qui n'est accessible qu'en écriture. Tu peux donc faire
let x = 3 in x
mais paslet _ = 3 in _
. C'est une info pour le compilo qui peut économiser des registres en ne sauvant pas la valeur retournée.La raison est que (>>) ne garde pas son résultat, alors que concatMap va me rendre une liste. Idéalement, il faudrait que je code une autre fonction qui me retourne la liste vide, mais j'ai eu la flemme, et le code ci-dessus a la même sémantique. (Et si tu te demandes l'intérêt d'évaluer une expression pour jeter son résultat, rappelle toi qu'on peut faire des effets de bord, donc que
let _ = foo () in 42
et42
ne sont pas pareil.)Pour ne pas comprendre
let test () = foo
, tu n'as pas du faire beaucoup de d'Ocaml.Ça déclare la *fonction* test qui n'a aucun argument. À chaque fois que tu l'appelles, foo est évalué.
let test = foo
déclare la *variable* test. foo n'est évalué qu'une fois, lors de la déclaration de test dont la valeur —qui ne changera plus jamais— est le résultat de l'évaluation de foo.[^] # Re: typage mou
Posté par reno . Évalué à 2.
Ca c'est très discutable, dans Eros il se sont rendu compte que dans certaines fonctions la valeur retournée n'aurait pas du l'être, ce qui peut être génant dans certains cas (capabilities).
Personellement je trouve que ce n'est pas une bonne idée d'avoir la derniere valeur d'une fonction retournée par defaut, je prefere que ce soit explicite.
Si tu considère 'return' comme étant trop lourd visuellement, alors '^' comme Smalltalk est un bon compromis..
[^] # Re: typage mou
Posté par daimrod . Évalué à 2.
[^] # Re: typage mou
Posté par reno . Évalué à 3.
2) Si tu fais vraiment du fonctionnel pur, ton programme ne sert à rien puisqu'il n'a pas d'effet sur l'extérieur.
3) Tout les langages fonctionnels ont des moyens de faire des effets de bords..
[^] # Re: typage mou
Posté par daimrod . Évalué à 2.
/o\ my bad, j'étais resté sur du Haskell.
> 2) Si tu fais vraiment du fonctionnel pur, ton programme ne sert à rien puisqu'il n'a pas d'effet sur l'extérieur.
Par forcément il peut retourner une valeur, puis tu interprètes cette valeur dans un autre programme écrit dans un autre langage.
(l'idée n'est pas de moi, j'ai lu un gars qui disait faire ça, un programme en haskell pour la partie « traitement » et un programme python pour le reste).
[^] # Re: typage mou
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 2.
2) Pas d'accord : il a un effet car tu peux mesurer son temps d'exécution s'il n'est pas paresseux. Et si ton programme est
if (P = NP) then true else loop-for-ever()
et que ton programme s'arrête, alors tu as un programme qui sert à prouver que P = NP.3) Non. Sans doute la plupart de ceux qui ont un évaluateur ou un compilateur. Mais le lambda calcul original, celui sur papier, ne peut pas faire d'effets de bords, et est bien un langage fonctionnel. Qui plus est, on passe encore du temps à travailler dessus, j'imagine que ce n'est pas pour rien !
[^] # Re: typage mou
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 2.
Je viens de relire vite fait le papier sur Eros (ICFP'07), et je ne vois ni capabilités, ni retour de valeur qui n'aurait pu l'être autrement.
Je demande qu'on m'éclaire sur ce point.
Et tu peux *toujours* ne pas retourner de valeur, c'est à ça que servent unit ou les types sommes que sont Maybe a en Haskell et 'a option en OCaml.
Et encore une fois, décider « la dernière sous expression évaluée dans e est la valeur retournée par e » permet d'économiser un mot clef.
Je trouve un return inutile, point barre.
Le ^ de smalltalk est un échappement, une rupture du flot de contrôle —contrairement au cas où l'on retourne la valeur de la dernière expression évaluée— et tu peux très facilement le simuler si tu as envie ; il est donc inutile de l'imposer dans la mesure où la majorité des gens s'en passent gaiement.
(define (ma-fun x)
(call/cc (lambda (^)
foo
(if bar
(^ h)
quux)
toto)))
Et une simple macro permet de rendre l'écriture du call/cc à la main inutile.
[^] # Re: typage mou
Posté par reno . Évalué à 2.
Mais tu as raison qu'un type de retour vide permet d'éviter ça..
[^] # Re: typage mou
Posté par Victor . Évalué à 3.
On est capable d'encoder plus d'information avec les types que avec ocaml (genre des contraintes et autre truc délires comme ça…)
[^] # Re: typage mou
Posté par ZankFrappa . Évalué à 10.
Haskell, lui, est « purement » fonctionnel : il ne dispose pas de constructions impératives. Il est également « paresseux » : les expressions ne sont calculées que quand c'est nécessaire. C'est le contraire des langages dits « stricts » (comme OCaml, mais aussi C, Java, Python… quasiment tout le monde en fait). Ça n'est pas à proprement parler une optimisation, parce que même si dans l'idéal ça évite de faire des calculs inutiles, en pratique ça demande davantage de tests, et ça peut rendre imprévisible le comportement du programme (notamment sa consommation mémoire). C'est une façon différente de programmer : ça t'autorise à flirter agréablement avec l'infini, en n'évaluant que ce qui est nécessaire.
Haskell dispose également de ce qu'on appelle des « typeclasses » : ils permettent une surcharge intelligente des opérateurs et des fonctions sur plusieurs types. OCaml n'en dispose pas, et ne peut par exemple pas utiliser le même opérateur d'addition pour les entiers et les flottants : l'opérateur (+) a le type int -> int -> int et l'opérateur (+.) a le type float -> float -> float. Ça a l'air chiant, en pratique ça passe dans ce cas précis. Dans d'autres cas ça peut être un peu irritant. Haskell lui est plus évolué : l'unique opérateur (+) a pour type (Num a) => a -> a -> a . Le a est à lire comme un paramètre de type : ainsi, ce type veut dire « si A est une instance de la classe Num, alors si b et c sont des valeurs de type A, b + c est de type A ». Note bien que ce sont des *types* qui sont des instances de *classes*, pas des valeurs.
D'autre part, certains problèmes sont naturellement impératifs : communiquer avec l'extérieur par exemple. Ceci se fait sans problème en séquençant des instructions Caml - par contre pour Haskell c'est plus difficile. Depuis un bon bout de temps maintenant, la seule façon conseillée de faire des entrées sorties dans ce langage est d'utiliser une construction élaborée appelée « monades ». C'est un mot qui fait peur aux débutants alors qu'il n'est pas très compliqué, mais ça ne s'explique pas en un paragraphe non plus. Les monades sont un concept provenant d'une branche très élaborée des mathématiques, appelée « théorie des catégories ». En gros, elles servent à séquencer des calculs - mais pas nécessairement de façon déterministe, c'est un concept plus général. Elles ne servent pas non plus uniquement à faire des entrées-sorties ou à simuler la programmation impérative. Et surtout, elles ne sont pas réservées à Haskell, il y a de nombreux langages modernes qui peuvent disposer de monades (OCaml ou C# par exemple).
Voilà.
(1) : au cas où tu ne connaîtrais vraiment pas les langages fonctionnels : si tu as déjà utilisé des langages impératifs, tu as certainement déjà manipulé des fonctions via des constructions comme les pointeurs de fonctions ou autres, et tu pourrais te dire donc que n'importe quel langage peut faire ça. En réalité, dans la famille des « fonctionnels » on regroupe les langages qui permettent de manipuler, et notamment de construire, des valeurs fonctionnelles. Par exemple, tu peux facilement définir un opérateur de composition de fonctions en Caml ou en Haskell. En C avec des pointeurs de fonctions, je ne vois pas vraiment comment faire.
[^] # Re: typage mou
Posté par khivapia . Évalué à 4.
[^] # Re: typage mou
Posté par lasher . Évalué à 5.
Mmmh, je trouve que c'est un peu déloyal de parler comme ça, à la limite de la malhonnêteté. [1] En OCaml, il y a bien inférence de type, mais dans le cas où tu mélanges différents types dans une fonction, et que tu n'as pas défini les interactions entre tous les types possibles que ta fonction accepte (le produit cartésien quoi), ben ce que renvoie ta fonction est un objet de type incomplet au mieux, qu'il faudra définir complètement par la suite. Quand tu n'as que quelques types à gérer tu t'en fous, mais dès que le nombre d'interactions entre types devient un peu complexe, ça commence à devenir pénible.
C'est pour ça que des langages type C, C++, Java, etc., déclarent les types des arguments etc. : pour « casser » la pénibilité en cas d'arguments multiples (entre autres choses hein). Et pourtant, si l'on excepte les types primitifs [2], Java utilise aussi la sûreté des types [3].
Mais quand on considère certains types de structures de données, genre (au pif) XML [4], ben là, chaque balise est un type, et dans un document XML classique, des types et des sous-types, y'en a ... fiou, tout plein. C'est là qu'interviennent des trucs (à ma connaissance pas implémentés dans les langages populaires, fonctionnels, ou impératifs) : le sous-typage sémantique. Y'a un langage preuve de concept qui a été créé pour l'occasion: CDuce. Il est dérivé des langages ML (d'ailleurs je crois bien qu'il nécessite OCaml pour être bootstrapé), mais sait correctement élaguer l'arbre des types/sous-types liés à un type donné. Fin bref, c'est très loin pour moi, tout ça, et mieux vaut aller voir de ce côté-là: http://cduce.org/
Tout ça pour dire que oui, OCaml est très bien, oui, il sait faire de l'inférence de type, mais clairement, non, ce n'est pas la panacée (par contre j'aime beaucoup son moteur de pattern matching pour le code, mais c'est une autre histoire).
[1] Je rigole hein ! :-)
[2] Oui, je sais, c'est un peu facile de dire ça ...
[3] Sur les objets donc... faire int toto = 3.2; va toujours fonctionner « à la C » et tronquer la valeur pour la stocker en tant qu'entier dans toto.
[4] XML qui inclut donc des types dans les types, ces types étant instanciés/présents (ou pas) en fonction des documents, etc.
[^] # Re: typage mou
Posté par Ontologia (site web personnel) . Évalué à 3.
Tu entend quoi par sous-type qu'il y en aurait plein ?
Pour moi du xml c'est tout simplement :
type xml =
| Element of (string * (string * string) list * xml list)
| PCData of string
Tes sous-types sémantique, ça serait prendre en compte le nom des balises et regarder la cohérence grammatical qu'il y a dans l'arbre ?
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: typage mou
Posté par lasher . Évalué à 5.
Donc ta balise, ce n'est plus une simple chaîne de caractères, c'est un type à part entière (et je te parle même pas des schémas, qui permettent justement de typer « pour de bon » le contenu de tes balises et de t'affranchir du « tout est chaîne »). Je te renvoie lâchement ici : http://cduce.org/papers.html pour plus d'infos, mais je t'avoue que l'article initial (« semantic subtyping ») est franchement difficile à lire. Y'a une version plus sympa (« A gentle introduction to semantic subtyping »), qui fait l'impasse sur le moteur de pattern matching, mais qui reste difficile à lire.
Dans tous les cas, tu te retrouves avec un type qui contient d'autres types (c'est ce que montre l'article original: il prouve ce qui était pure conjecture par ailleurs : il y a une relation ensembliste entre un type et ses sous-types).
Au final, si tu as un arbre XML à traiter (par exemple pour trouver une certaine information), CDuce (et d'autres langages, genre XQuery, à supposer qu'ils bénéficient du même genre de fonctionnalités que CDuce dans leur implémentation) devrait être capable de rapidement élaguer l'arbre, pour rapidement trouver une réponse à la recherche faite dans le document.
[^] # Re: typage mou
Posté par reno . Évalué à 8.
Pour Haskell, une critique sérieuse est que l'évaluation paresseuse par défaut rend difficile l'évaluation des performances: des petites modifications peuvent induire des grandes variations de performances..
L'autre critique sérieuse est que ce langage est difficile à apprendre.
[^] # Re: typage mou
Posté par daimrod . Évalué à 2.
Il parait qu'Haskell perce un peu dans le domaine bancaire, pour la sécurité qu'il offre.
> Pour Haskell, une critique sérieuse est que l'évaluation paresseuse par défaut rend difficile l'évaluation des performances: des petites modifications
> peuvent induire des grandes variations de performances..
Je ne vois pas trop quelle modification mineure pourrait induire les variations de performances dont tu parles.
Parce qu'il faut un changement d'algo pour passer de l'un à l'autre. C'est un changement « d'approche ».
> L'autre critique sérieuse est que ce langage est difficile à apprendre.
Il y a quelques concepts un peu perturbant au départ c'est vrai, mais je trouve cela tellement amusant. C'est comme ré-apprendre à programmer/penser.
[^] # Re: typage mou
Posté par reno . Évalué à 2.
Je n'ai plus en tête le lien du papier, désolé.
Mais je connais un exemple proche: la récursion terminale très utilisée dans les langages fonctionnels: il est très facile de passer d'une récursion terminale a une récursion non terminale, ce qui change beaucoup les performances..
Et si le langage n'a pas de mot-clef pour différencier les appels de fonctions terminales des autres, le compilateur ne te préviendra même pas que tu viens de flinguer tes performances/ton nombre maximum de récursion..
[^] # Re: typage mou
Posté par daimrod . Évalué à 2.
Par exemple, foldl et foldl'.
Après pour le coup de la récursivité terminale ou non, bah c'est comme pour tous les langages je suppose, tu as des algos plus ou moins efficaces
mais tu ne vas pas indiquer pour chaque fonction -- dans son nom -- quelle stratégie tu utilises.
On va généralement l'indiquer dans la doc ou dans les commentaires.
> Et si le langage n'a pas de mot-clef pour différencier les appels de fonctions terminales des autres, le compilateur ne te préviendra même pas que tu
> viens de flinguer tes performances/ton nombre maximum de récursion..
Tu aurais un exemple de langage qui fait ça ?
[^] # Re: typage mou
Posté par reno . Évalué à 4.
[^] # Re: typage mou
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 3.
Savoir si un appel de fonction est en position terminale ou pas est décidable, et je n'ai pas souvenir de situation où un appel non terminal était préférable (ce qui ne veut pas dire qu'il n'y en a pas).
Et si j'écris
let rec fact n =
if n = 0 then 1
else n * ((fact (n-1))_terminal)
ce qui est absolument faux vu qu'il reste à multiplier par n après que l'appel récursif a retourné fact (n-1), il va se passer quoi ?
[^] # Re: typage mou
Posté par daimrod . Évalué à 3.
[^] # Re: typage mou
Posté par reno . Évalué à 3.
Pour répondre, à Axioplase note que je n'ai jamais dit qu'un appel de fonction non terminal pouvait être préférable à un appel de fonction terminal.
J'ai juste dit que s'il n'y a pas d'annotation, il est très facile dans une maintenance de modifier une fonction en rendant le dernier appel non terminal..
[^] # Re: typage mou
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 2.
Selon moi, plus qu'offrir des avantages (je n'en vois pas encore un seul), ça n'offre que des inconvénients : vu que tu stockes sur la pile tes adresses de retour, tu risques en mode débug de créer des erreurs inexistantes en mode « bon sens » via des débordement de pile. Et c'est encore pire quand tu as du parallélisme ou de l'évaluation paresseuse car tu peux ne plus savoir du tout qui a alloué quoi ni quand…
Le fait qu'on puisse le faire ne me justifie toujours pas qu'on veuille le faire ni que ce soit une bonne idée. L'optimisation des appels en position terminal date de la fin des années 70, et c'est sans doute pas pour rien que la norme du langage Scheme impose que tout appel de fonction en position terminale soit n'alloue pas de pile.
Vouloir remplacer les appels terminaux par des appels qui allouent sur la pile revient à vouloir remplacer une boucle while par des appels récursifs de fonction en C (qui allouent donc sur la pile). Si c'était une bonne idée, j'imagine que ça se saurait/ferait.
[^] # Re: typage mou
Posté par Moonz . Évalué à 6.
func printFloat(f float) {
print(f)
}
func main() {
var x int = 5
printFloat(x)
}
Il vous faut quoi de plus pour que ce soit du typage fort ?
[^] # Re: typage mou
Posté par Victor . Évalué à 1.
Voir par exemple :
http://debasishg.blogspot.com/2010/08/using-generalized-type(...)
Ou encore :
http://debasishg.blogspot.com/2010/09/towards-generic-apis-f(...)
[^] # Re: typage mou
Posté par Moonz . Évalué à 6.
[^] # Re: typage mou
Posté par Victor . Évalué à 3.
Mais je pense que les gens ils veulent des trucs cools comme ça :)
(et aussi je voulais encore me la ramener avec du Scala, désolé :>)
[^] # Re: typage mou
Posté par Moonz . Évalué à 2.
Et j’ai bien peur que ça finisse comme la métaprogrammation en C++ tout ça…
[^] # Re: typage mou
Posté par Jux (site web personnel) . Évalué à 3.
Par contre au niveau de la syntaxe, je trouve que ça n'est pas super clair. J'ai l'impression qu'il y a un peu une tendance à abuser de la définition de nouveaux opérateurs.
Tiré de l'article cité ci-dessus :
# A =:= B, which mandates that A and B should exactly match
# A <:< B, which mandates that A must conform to B
# A A <%< B, which means that A must be viewable as B
Les opérateurs ne sont pas franchement explicites pour quelqu'un qui n'utilise pas ça tous les jours. Pourquoi ne pas utiliser des mots-clés genre "conform" "viewable" et "is" ou que sais-je ? Ca ne rendrait pas tout ça un peu plus clair ?
Qu'en pense ceux qui font du Scala régulièrement ? On s'y habitue facilement une fois qu'on est plongé dedans ?
[^] # Re: typage mou
Posté par lasher . Évalué à 3.
[^] # Re: typage mou
Posté par Ontologia (site web personnel) . Évalué à 4.
Et comme tous professionnel dans sa branche, ça te permet de jargonner et de te sentir assuré par la particularité de tes connaissances ;-)
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: typage mou
Posté par lasher . Évalué à 2.
[^] # Re: typage mou
Posté par MsieurHappy . Évalué à 2.
Quel programmeur n'a jamais eu la rébarbative tâche d'écrire une fonction de comparaison pour un objet/structure avec beaucoup de champs à comparer ? On se retrouve avec un arbre de if/else, ou autre structure de contrôle. Mes premiers pas en Haskell furent le théâtre d'abominables et naïfs
compare a b = case compare (field1 a) (field1 b) of
EQ -> case compare (field2 a) (field2 b) of
EQ -> case compare (field3 a) (field3 b) of
EQ -> compare (length (field4 a)) (length (field4 b))
ord -> ord
ord -> ord
ord -> ord
J'ai donc mis mon cerveau en branle pour profiter de la richesse de Haskell: généricité, type class, fonctions d'ordre supérieur, composition, applications partielles, inférence de type, etc.
En Haskell, on a la chance d'avoir le type Ordering, qui représente le résultat d'une comparaison par 3 constructeurs, plutôt que des entiers:
data Ordering = LT | EQ | GT
qui est une instance de Monoid, ce qui nous permet d'utiliser mappend, et mconcat en particulier, sa généralisation sur les liste:
class Monoid a where
mempty :: a
mappend :: a -> a -> a
mconcat :: [a] -> a
instance Monoid Ordering where
mempty = EQ
LT `mappend` _ = LT
EQ `mappend` y = y
GT `mappend` _ = GT
En outre, avec la fonction Data.Ord.comparing, on peut aisément comparer un champ, ou plus génériquement une propriété, des valeurs à comparer:
comparing :: Ord a => (b -> a) -> b -> b -> Ordering
Il nous est maintenant possible d'écrire facilement un enchaînement comparaison de propriétés, dont on retourne le résultat dès qu'on a divergence (LT ou GT):
compare a b = mconcat [comparing field1 a b, comparing field2 a b, comparing field3 a b, comparing (length . field4) a b]
Mais c'est encore très redondant et surtout généralisable! On aurait qu'à avoir la liste des champs/propriétés à comparer!
Cependant, comme une liste a un type donné, on ne peut pas voir une liste hétérogène.
C'est là qu'intervient les existential types! On va créer une fine enveloppe pour stocker nos propriétés à comparer, en garantissant le type d'entrée et la possibilité de comparer le type de sortie:
data Property a = forall p. Ord p => Prop (a -> p)
Il nous reste alors plus qu'à jouer du mconcat et du comparing pour écrire une fonction permettant de comparer séquentiellement sur une liste de propriété:
compareProps :: [Property a] -> a -> a -> Ordering
compareProps ps a b = mconcat $ map (\(Prop p) -> comparing p a b) ps
On peut maintenant réécrire notre comparaison plus simplement:
compare = compareProps [Prop field1, Prop field2, Prop field3, Prop (length . field4)]
Le code en question, avec les imports et tout, dans un exemple un peu plus concret: http://media.msieurhappy.net/pub/Properties.hs
Voilà, entre autre chose, ce que peut permettre un puissant système de type. :)
PS: J'ai essayé de faire au mieux, mais ma p'tite présentation est probablement très confuse et impénétrable si on a pas quelques notions de Haskell. Je m'en excuse par avance. /o\
[^] # Re: typage mou
Posté par hocwp (site web personnel) . Évalué à 1.
> (defstruct toto x y z)
> (defparameter a (make-toto :x 10 :y 20 :z 10))
> (defparameter b (make-toto :x 10 :y 20 :z 10))
> (equalp a b) => T
Si on ne veux comparer que quelques champs, on peut écrire une petite macro qui va générer l'arbre if/else à notre place à la compilation. Et on pourra écrire un truc du genre :
> (fields-equal a b :x :z) => T
Bon je sors, j'ai un petit tutoriel à lire http://lisperati.com/haskell/ :-)
[^] # Re: typage mou
Posté par MsieurHappy . Évalué à 2.
La majorité du temps, Haskell peut déduire tout seul l'opération d'équalité. Il suffit à la déclaration du datatype d'indiqué de dériver Eq
data Foo a b c = Foo { x :: a, y :: b, z :: c } deriving (Eq)
> Foo 10 20.0 "10" == Foo 10 20.0 "10"
True
[^] # Re: typage mou
Posté par hocwp (site web personnel) . Évalué à 1.
(defmacro fields-equal (a b &rest fields)
`(and ,@(loop for f in fields
collect `(equal (,f ,a) (,f ,b)))))
(defstruct toto a b c x y z)
(defparameter objet1 (make-toto :a 10 :b 20 :c "plop" :x 'plop :y 10.5 :z 10))
(defparameter objet2 (make-toto :a 10 :b 50 :c "plop" :x 'plop :y 10.5 :z 1001))
(fields-equal objet1 objet2 toto-a toto-c toto-y) => T
(fields-equal objet1 objet2 toto-a toto-c toto-y toto-z) => NIL
(macroexpand-1 '(fields-equal objet1 objet2 toto-a toto-c toto-y toto-z))
=> (AND (EQUAL (TOTO-A OBJET1) (TOTO-A OBJET2))
(EQUAL (TOTO-C OBJET1) (TOTO-C OBJET2))
(EQUAL (TOTO-Y OBJET1) (TOTO-Y OBJET2))
(EQUAL (TOTO-Z OBJET1) (TOTO-Z OBJET2)))
Évidement, on peut l'améliorer pour ne pas avoir à taper toto-*. On peut aussi imaginer faire la comparaison entre deux objets de structures différentes partageant des champs en commun (amis du type fort, bonjour :-) ).. Mais je ne suis pas sûr que ce soit vraiment judicieux.
[^] # Re: typage mou
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 2.
C'est d'ailleurs ainsi que c'est implanté en Caml, et sans doute en Haskell.
Et ça se fait en CL assez facilement.
(Après, il serait sans doute judicieux de passer par des méthodes génériques pour pouvoir traverser automatiquement des listes, vecteurs…)
(defmacro init-order-table ()
(defvar *order-table* (make-hash-table :test #'eql)))
(defmacro defconstant-ordered (&rest constants)
(cons 'progn
(loop for c in constants
for i from 0
collect
`(setf (gethash ',c *order-table*) ,i))))
(defmacro compare (sym1 sym2)
`(let ((v1 (gethash ',sym1 *order-table*))
(v2 (gethash ',sym2 *order-table*)))
(cond
((= v1 v2) 'EQ)
((< v1 v2) 'LT)
(t 'GT))))
(init-order-table)
(defconstant-ordered cFoo cBar)
(list
(compare cFoo cBar)
(compare cBar cFoo)
(compare cBar cBar))
type foo = Foo | Bar;;
[(compare Foo Bar);
(compare Bar Foo);
(compare Bar Bar)];;
[^] # Re: typage mou
Posté par CrEv (site web personnel) . Évalué à 4.
ben franchement ça m'a l'air bien compliqué, ou plutôt ça donne l'impression de devoir se casser la tête pour pas grand chose finalement (juste comparer les champs de deux structures...)
var compare = function(a, b, props) {
var prop, i, l = props.length;
for(i = 0; i < l; i++) {
prop = props[i];
if(a[prop] !== b[prop]) {
return false;
}
}
return true;
};
compare(a, b, ["field1", "field2", "field3"]);
> Quel programmeur n'a jamais eu la rébarbative tâche d'écrire une fonction de comparaison pour un objet/structure avec beaucoup de champs à comparer ?
Du moment qu'on peut travailler avec introspection je ne vois pas vraiment le problème en fait...
ou alors j'ai pas capté le problème...
[^] # Re: typage mou
Posté par Victor . Évalué à 2.
ben franchement ça m'a l'air bien compliqué, ou plutôt ça donne l'impression de devoir se casser la tête pour pas grand chose finalement (juste comparer les champs de deux structures...)
Ta solution ne répond pas au problème, on veut que "field1", "field2", "field3" soit des fields d'une structure de donnée qui soit typée, là tu manipule une espèce de map.
Ici le compilateur ne peut PAS vérifier que "field1", "field2", "field3" existe bien dans a et b quand tu fais appel à compare, donc tu dois TE faire confiance (ou à un des 25 mecs avec qui tu bosses :).
Sinon
Du moment qu'on peut travailler avec introspection je ne vois pas vraiment le problème en fait...
C'est pareil, tu dois te faire confiance pour ne pas faire de bêtises.
Alors sur un exemple comme ça, c'est pas la fin du monde (et encore avec ta solution, ça ne marche que sur les maps...), mais sur des plus gros trucs plus complexes ça fait mal à la tête de tout tester avec son cerveau :)
[^] # Re: typage mou
Posté par Moonz . Évalué à 2.
Heu, non, en Javascript, x.foo et x["foo"] sont équivalents
[^] # Re: typage mou
Posté par Victor . Évalué à 2.
[^] # Re: typage mou
Posté par Moonz . Évalué à 2.
[^] # Re: typage mou
Posté par Victor . Évalué à 1.
Ou alors ça te dit undefined à la compilation ?
Genre quand tu écris :
compare(a, b, ["field1", "field2", "field3"]);
Ça te dit : oulala attention, tu écris un truc pas très très possible là, parce que field3, ça va être undefined ?
[^] # Re: typage mou
Posté par Moonz . Évalué à 1.
En même temps, en JavaScript, ça risque d’être compliqué ;)
[^] # Re: typage mou
Posté par CrEv (site web personnel) . Évalué à 1.
J'avais bien compris, mais c'est écrit justement avec un langage me permettant de parcourir et d'utiliser les membres d'un objet en fonction de leur nom. C'est bien le but, non ?
Et oui, en quelque sorte tout est map en javascript... mais le problème n'est absolument pas là.
> Ici le compilateur
ha, j'avais pas compris que le but était de se reposer sur un compilo (perso j'aime pas me reposer dessus...)
> le compilateur ne peut PAS vérifier que "field1", "field2", "field3" existe bien dans a et b quand tu fais appel à compare
ok, pardon :
// a rajouter dans le for
if(!(prop in a && prop in b)) {
return false;
}
hop hop, je sais maintenant que mes champs sont dedans.
> et encore avec ta solution, ça ne marche que sur les maps...
et maintenant que tu sais que ça marche avec n'importe quel objet ?
[^] # Re: typage mou
Posté par lasher . Évalué à 1.
Y'a suffisamment de cas où le compilateur ne fait pas bien son boulot pour lui laisser l'occasion de briller quand c'est plutôt chiant à faire à la main, tu ne trouves pas ?
[^] # Re: typage mou
Posté par Moonz . Évalué à 0.
Qu’on soit clair : je n’ai jamais dit que ce genre de fonctionnalité n’était pas intéressante dans l’absolu. Simplement, je me pose la question du prix à payer pour de telles fonctionnalités. Si c’est pour se taper ensuite des pans entiers de code qui font de la « métaprogrammation » à la C++, merci mais non merci (vous avez déjà essayé de débugger un truc comme ça ? Un an après ? Écrit par quelqu’un d’autre ? Alors, oui, c’est type-safe et puissant, mais…). Si c’est pour avoir un langage qui nécessite une thèse en mathématiques pour comprendre pourquoi le compilateur râle sur ce bout de code alors qu’intuitivement il devrait pas, idem. Et je suis également assez sensible à la complexité du compilateur lui-même, du reste.
Je crois qu’on va là refaire le débat séculaire du « worse is better » : http://www.jwz.org/doc/worse-is-better.html :). Et étant clairement du côté worse-is-better, c’est la raison pour laquelle je me méfie de Scala et privilégie Go. Ce n’est pas un hasard si go a tant de succès auprès de suckless & co.
Enfin, je dis ça, mais apprendre Haskell est sur ma TODO-list depuis un moment ;) (plus pour ma culture que pour une réelle utilisation toutefois)
[^] # Re: typage mou
Posté par lasher . Évalué à 5.
Le truc, c'est que ce qui te semble simple, voire évident, dans le code que tu as montré se transforme en code spaghetti à force de rajouter une condition par-ci ou une autre par-là. C'est ce que je voulais dire par « laisser le compilateur briller là où il le peut ». Un exemple tout bête: une multiplication de matrice.
Le code original (naïf et tout):
void matmul(const size_t m, const size_t n, const size_t k,
const double alpha, const double *a, const double *b,
const double beta, double *c)
{
for (size_t i = 0; i < m; ++i)
for (size_t j = 0; j < n; ++j)
for (size_t l = 0; l < k; ++l)
c[i*n+j] = beta * c[i*n+j] + alpha * a[i*k+l] * b[l*n+j];
}
Bon, tu peux t'embêter à faire tout un tas d'optimisations super intelligentes (et connues depuis 30 ans), du genre promotion scalaire, inversion de boucles, et tuilage, etc., ce qui pourrait donner un truc du genre :
void matmul(const size_t m, const size_t n, const size_t k,
const double alpha, const double *a, const double *b,
const double beta, double *c)
{
for (size_t i = 0; i < m; ii += TILE_I)
for (size_t l = 0; l < k; l += TILE_L)
for (size_t j = 0; j < n; j += TILE_J)
for (size_t ii = i; ii < MAX(i+TILE_I,m); ++ii)
for (size_t jj = j; jj < MAX(j+TILE_J,n); ++jj) {
acc = c[ii*n+jj] * beta;
for (size_t ll = l; l < MAX(l+TILE_L,k); ++ll) {
acc = c[ii*n+jj] + alpha * a[ii*k+ll] * b[ll*n+jj];
}
c[ii*n+jj] = acc;
}
}
Bon, je ne dis même pas que ce code est optimal (il est loin de l'être). Un bon exemple concernant ce genre de transformations se trouve ici : http://www.spinellis.g/blog/20090420/
Cependant, si je te dis que y'a toute une théorie qui existe déjà concernant les nids de boucle, et que ce genre d'optimisation peut-être faite par le compilateur sans que tu aies à lever le petit doigt, tu seras content non ? Ben le typage fort permet justement ce genre d'optimisations (enfin pas le tuilage, mais d'autres transformations/simplifications de code). Du coup quand je te vois faire ce que tu fais en JS (ou je ne sais quel autre langage), en rajoutant condition après condition et en disant « facile ! » en fonction de ce qu'on te dit que le compilateur sait déjà faire, je tique un peu. :)
[^] # Re: typage mou
Posté par Moonz . Évalué à 2.
Ton lien est mort
> tu seras content non ?
Oui, mais je fais la différence entre optimiser un truc simple qui marche et créer un truc complexe de manière innée et inhérente, c’est-à-dire qui est impossible à implémenter simplement.
Ceux qui ont déjà eu des bugs en -O4 qui disparaissent en -O0 comprendront ce que je veut dire, pour les autres, je n’ai qu’une chose à dire : vous comprendrez tôt ou tard :)
Il faudrait que quelqu’un écrive « The Fallacies of Programming languages » sur le modèle de « The Eight Fallacies of Distributed Computing », tiens. On y trouverait, entre autre :
- le compilateur n’est pas buggué
- la librairie standard n’est pas bugguée
- les optimisations améliorent toujours les performances
- les optimisations n’influent sur rien d’autre que les performances
- un langage cohérent et élégant est facilement prévisible
[^] # Re: typage mou
Posté par lasher . Évalué à 3.
[^] # Re: typage mou
Posté par lasher . Évalué à 3.
Cela étant dit: si tu prends n'importe quel guide sur l'optimisation de code (disons le manuel d'Intel sur la question par exemple http://www.intel.com/Assets/PDF/manual/248966.pdf, ou le site de A.Fog, http://www.agner.org), ou surtout des manuels plus haut-niveau (pour les gens qui ne veulent/peuvent pas passer le temps qu'il faut à micro-optimiser leur code), les méthodologies proposées impliquent souvent de compiler à différents niveaux d'optim (-O0,..., -O3), et de prendre un jeu d'essai représentatif -- bref, de faire à la main ce que certains compilateurs (icc, et normalement gcc aussi, par exemple) savent faire depuis un moment: de la compilation guidée par profilage.
De plus, que -O3 puisse ralentir un programme, je le crois volontiers; qu'il donne des résultats faux (ou même que l'optimisation a eu un effet de bord surprenant, disons), à moins d'un bug dans le compilateur, c'est plutôt que l'utilisateur a fait des hypothèses quant au langage/à la machine qu'il utilise (je parle d'expérience).
Concernant la cohérence et l'élégance d'un langage et sa prévisibilité, je ne suis pas certain de comprendre ce que tu veux dire par là. La plupart du temps (mais clairement pas toujours), plus de concision implique plus de clarté, mais cela suppose néanmoins une compréhension du langage, et de comment il fonctionne. J'ai l'impression qu'une bonne partie des reproches faits aux langages « différents » (qu'ils soient fonctionnels, tels que ML, Haskell, LISP, déclaratifs tels PROLOG, ou bien juste « glu » genre Perl) est qu'ils ne fonctionnent pas comme leurs cousins impératifs tirés du C. J'ai exactement le même problème avec Fortran par exemple, et pourtant il n'est pas si éloigné du C que ça (en supposant qu'on passe à Fortran 90 au minimum pour avoir la forme libre de syntaxe).
[^] # Re: typage mou
Posté par MsieurHappy . Évalué à 1.
Et bien plus encore, car le Property enveloppant une fonction, on peut effectuer des traitements sur les champs avant de les comparer, encore une fois, avec la garantie sur les types.
Si je vais à l'essentiel du fonctionnement de la méthode expliquée, j'ai besoin que de 2 lignes:
data Property a = forall p. Ord p => Prop (a -> p)
compareProps ps a b = mconcat $ map (\(Prop p) -> comparing p a b) p
Pour illustrer les traitements possible, field2 est une liste d'entier dont on comparera la somme plutôt que les éléments, field3 est une chaîne de caractères qu'on comparera en négligeant la case:
compareProps [Prop field1, Prop (sum . field2), Prop (map toLower . field3)] a b
[^] # Re: typage mou
Posté par CrEv (site web personnel) . Évalué à 3.
var compare = function(a, b, props) {
var prop, field, comp, i, l = props.length;
for(i = 0; i < l; i++) {
prop = props[i];
field = prop.field;
if(!(field in a && field in b)) {
return false;
}
if("comp" in prop) {
comp = prop.comp;
if(!(comp in a[field] && comp in b[field]) {
return false;
}
if(a[field][comp]() !== b[field][comp]()) {
return false;
}
} else if(a[field] !== b[field]) {
return false;
}
}
return true;
};
compare(a, b, [{field: "field1"}, {field: "field2", comp: "sum"}, {field: "field3", comp: "toLowerCase"}]);
Bon, évidemment sum, toLowerCase doivent exister. Le code devient plus gros, mais c'est juste que le map n'existe pas de la même manière, mais au final je suis toujours totalement dynamique et ma comparaison de champ reste facile et simple à écrire.
Non pas que je veuille que haskell ne serve à rien, mais j'ai toujours pas compris l'intérêt à se casser la tête. Peut-être par rapport à des langages pauvres (comme c/c++/java par exemple) mais par rapport à js, as3, surement ruby, peut-être python ça me parait bien complexe (faut vraiment réfléchir pour comprendre le code haskell un peu plus haut, d'ailleurs le cheminement n'est pas simple, alors que c'est bidon, juste comparer une liste de propriété)
Maintenant, je pense bien que ce genre de paradigme à une utilité, enfin j'espère ;-)
[^] # Re: typage mou
Posté par MsieurHappy . Évalué à 1.
Mon code tient en 2 lignes (hors imports et la signature de la fonction, cette dernière étant uniquement pour aider à la compréhension du code, pour peu que le système de type de Haskell ne soit pas du chinois pour soi. ;)) ce qui me semble assez élégant et succinct.
En outre, le propos n'était pas tant de débattre sur l'utilité pratique de mon bout de code que de montrer les possibilités d'un système de type fort, statique et puissant. J'en convient, ça n'a probablement aucun intérêt quand on fait du JS, mais là n'est pas le propos. ;)
ha, j'avais pas compris que le but était de se reposer sur un compilo (perso j'aime pas me reposer dessus...)
L'exploitation du compilateur permet 1/ d'éviter des erreurs de programmations qu'on découvre qu'à l'exécution 2/ d'éviter un surcoût à l'exécution pour valider les données.
[^] # Re: typage mou
Posté par CrEv (site web personnel) . Évalué à 3.
ok, j'avais zapé ce point...
> en 2 lignes (hors imports et la signature de la fonction
Si je met ma méthode dans un import, mon code tiens en une ligne (hors import et signature de la fonction)...
> En outre, le propos n'était pas tant de débattre sur l'utilité pratique de mon bout de code que de montrer les possibilités d'un système de type fort, statique et puissant.
ha mais je suis totalement d'accord. C'est juste que, ne connaissant pas les langages de ce type, à la lecture du cheminement pour écrire ton morceau de code, j'ai eu l'impression que c'était compliqué pour faire trois fois rien. Et j'ai l'impression que cette complexité vient directement du type de langage d'où le fait de montrer qu'on peut faire plus "simple" (au niveau du raisonnement, de la logique du code) pour arriver à une fonctionnalité assez équivalente.
Maintenant, il y a surement plein de cas où ce serait le contraire je pense... (ok, peut-être qu'il faudra un jour que je prenne le temps de regarder ce genre de paradigme...)
> L'exploitation du compilateur permet 1/ d'éviter des erreurs de programmations qu'on découvre qu'à l'exécution
oui, mais mon avis est que lorsqu'on se repose trop souvent sur un compilateur, on oublie de réaliser les tests soit-même. Et on se retrouve avec une tripoté de "codeurs" qui font : 2 lignes de code, CTRL-S, je regarde la sortie du compilo, je corrige si nécessaire, sinon je passe à la suite.
Le problème est que ces personnes, en se reposant exagérément sur le compilo ne savent finalement plus coder correctement mais seulement réagir face à une erreur à la compile. Et résultat, de part cette faillibilité on se retrouve avec plein de trucs zarb à l'exécution car c'est mal réfléchi et que le compilo ne peut pas tout faire.
[^] # Re: typage mou
Posté par MsieurHappy . Évalué à 4.
L'idée était de montrer l'utilisation de multiples facettes du système de type et que ça pleine compréhension permet d'écrire du code sûr et néanmoins court.
j'ai l'impression que cette complexité vient directement du type de langage d'où le fait de montrer qu'on peut faire plus "simple" (au niveau du raisonnement, de la logique du code) pour arriver à une fonctionnalité assez équivalente
C'est la nature de l'approche qui est très différente. Et c'est bien là qu'on constate la différence de paradigme: fonctionnel vs impératif (à objets). L'apparente complexité provient à mon avis qu'en Haskell on manipule des concepts plus élaborés et plus abstraits, mais le code s'en trouve simplifiée: composition + fonction d'ordre supérieur. Alors qu'en JavaScript on manipule des concepts plus basics (et plus familiers), mais on se retrouve avec un code plus complexe, avec de multiples branchements conditionnels, et plus sujet aux erreurs de programmation. En outre, le code JS n'est même pas équivalent.
Si j'en fais un module complet:
{-# LANGUAGE ExistentialQuantification #-}
module Properties where
import Data.Monoid (mconcat)
import Data.Ord (comparing)
data Property a = forall p. Ord p => Prop (a -> p)
compareProps :: [Property a] -> a -> a -> Ordering
compareProps ps a b = mconcat $ map (\(Prop p) -> comparing p a b) ps
(les imports sont de la lib standard)
Si quelqu'un a l'équivalent dans un autre langage de programmation, ou mieux, qu'il n'hésite pas. :)
mais mon avis est que lorsqu'on se repose trop souvent sur un compilateur, on oublie de réaliser les tests soit-même
C'est clair que c'est pas parce que ça compile que ça fonctionne correctement. Ça ne remplace pas l'écriture de tests. Mais la cohérence forcée du typage par le langage (parce que ça marche aussi bien avec un interpréteur qu'un compilateur en Haskell) permet de formaliser une partie du code et d'offrir des garanties que tu ne peux pas offrir en JS. Alors c'est sûr que pour un script JS sur une page Web l'intérêt est limité, mais dans plein d'autres applications, on va apprécier cette fonctionnalité.
[^] # Re: typage mou
Posté par Victor . Évalué à 4.
Mais la cohérence forcée du typage par le langage (parce que ça marche aussi bien avec un interpréteur qu'un compilateur en Haskell) permet de formaliser une partie du code et d'offrir des garanties que tu ne peux pas offrir en JS. Alors c'est sûr que pour un script JS sur une page Web l'intérêt est limité, mais dans plein d'autres applications, on va apprécier cette fonctionnalité.
Je rebondirais même là dessus pour ajouter que ça peut parfois remplacer les tests.
L'exemple le plus connu et qui fait vraiment mal au cul quand on se remet au Java après avoir fais du Scala, c'est tout ces tests à écrire juste pour s'assurer qu'il n'y a pas un null qui traine.
La contrainte : "{ce paramètre,valeur de retour,etc…} ne peut pas être null" peut être exprimée avec des types !
Et bin on peut faire pareil avec pleins d'autres contraintes encore plus sympa :)
(Et là je ne parle que de type, contrairement à msieur happy qui nous parlait de prog fonctionnelle ET de types :)
[^] # Re: typage mou
Posté par lasher . Évalué à 2.
Et qu'il n'existe pas d'outils en Java pour correctement vérifier qu'une variable est non-null est une chose. Typiquement lors de l'écriture d'une méthode, un IDE comme Eclipse signalera toute variable susceptible d'être non-initialisée, à l'exception des variables passées en paramètre. Après, qu'il faille un outil pour vérifier que l'articulation des méthodes (le graphe d'appel des fonctions quoi) passe bien des arguments non-null (en supposant que ce ne soit pas autorisé), c'est un autre problème... Cela dit je n'ai pas fait de Java depuis longtemps, et je me demande si les ajouts syntaxiques au langage (annotations, etc) ne permettent pas de détecter ce genre de trucs ...
[^] # Re: typage mou
Posté par Victor . Évalué à 3.
Mais on ne peut pas encoder cette contrainte au niveau des types (en fait on pourrait dire que findbug étant le typage pour encoder ce genre de chose, c'est juste que c'est un typage pas compris par le compilateur Java mais compris par le vérifieur findbugs).
Donc Java a un typage fort, mais il est pas suffisamment fort, contrairement à Georges.
[^] # Re: typage mou
Posté par lasher . Évalué à 4.
[^] # Re: typage mou
Posté par Bruno Michel (site web personnel) . Évalué à 3.
Personne n'a de liens à ce sujet ? Ce serait juste une légende urbaine ?
[^] # Re: typage mou
Posté par Pierre Jarillon (site web personnel) . Évalué à 0.
[^] # Re: typage mou
Posté par Ontologia (site web personnel) . Évalué à 8.
J'ai l'impression qu'il y a pas vraiment d'étude sur le sujet. Après mon expérience perso me fait penser que "typage fort => Moins de bugs".
J'ai pratiqué, dans l'ordre le :
- Basic (quand j'étais gamin, ya 20 ans donc)
- Pascal (pas mal)
- C
- Ocaml
- (SQL)
- Lisaac
- Java
- Ruby
Typiquement, en caml, quand le compilateur me dit "ok" en général ça marche. Mais c'est pas très représentatif, parce que je l'utilise surtout dans des problématique ou je dois manipuler des grammaires.
Pour les langages objets, entre java, lisaac et ruby, ce qui est indéniable dans mon expérience, c'est les Call On Null.
En java et ruby, je m'en prend plein partout à l'exécution. D'où une boucle, trouver où c'est, corriger, relancer/retester.
En Lisaac, pas mal de Call on Null sont détectés à la compilation, et c'est un vrai gain (surtout depuis l'ajout param w_null du compilateur dont la stable est en préparation, qui nous affiche tous les call on null potentiels du code).
Ca t'oblige à faire une passe sur ton code lorsque tu le compiles.
C'est un peu vexant au début, mais tu te retrouve avec beaucoup moins de problèmes.
Pour le reste, le typage avancé et fort, et je pense surtout dans mon expérience en Lisaac et en Ocaml, me permette surtout de faire des choses très avancées, très courte, très propre, qui aurait été des bidouillage infames en Java, voire des fois en Ruby et qui auraient donc été super bugués.
C'est donc plutôt en rendant le code plus "clair" pour quelqu'un qui a l'esprit assez "théorique" pour comprendre que ça diminue le nombre de ligne, simplifie le code et le rend moins sujets à bug.
C'est plus une question d'expressivité.
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: typage mou
Posté par GuieA_7 (site web personnel) . Évalué à 3.
# Question de feeling...
Posté par jideel . Évalué à 6.
Serieusement, ça me réconcilie avec le code, alors que <mode Fuuuuuuuuu>j'en avais marre d'etre entouré de petit peteux qui s'imaginent tout connaitre parce qu'ils viennent de découvrir comment faire une factory en Java</mode Fuuuuuuuuu>.
Je recommande à tous ceux qui voudrait essayer de tester GoPlay (dans misc/).
My 2 cents.
# Intéressant pour les idées ... mais non
Posté par Jonathan MERCIER (site web personnel) . Évalué à 3.
Je me suis mis au D, ayant l'habitude de java, c++ et python (et eiffel pour les connaisseurs). J'ai trouvé un langage qui a fusionne les avantages de ces trois langages.
Toutefois tout n'est pas rose le langage est relativement jeune du coup on croule pas sous les bibliothèque et on découvre de temps en temps des bugs. Ceci est toutefois rattrapé par une communauté proche a l'écoute et dont les fixes arrivent vite une fois détecté.
Pour moi un langage a suivre le D, j'ai éliminé le scala a cause de la JVM mais j'en convient qu'il est intéressant
[^] # Re: Intéressant pour les idées ... mais non
Posté par Bruno Michel (site web personnel) . Évalué à 8.
Heu, c'est très relatif, D existe depuis plus de 10 ans et est presque aussi vieux que PHP ou Ruby.
> Ceci est toutefois rattrapé par une communauté proche a l'écoute
Mwais, ce n'était pas vraiment mon ressenti. Par exemple, il y a 2 bibliothèques standards en D, incompatibles entre elles.
[^] # Re: Intéressant pour les idées ... mais non
Posté par mosfet . Évalué à 2.
D'autres mauvais arguments ?
Nan sérieusement je suis vraiment fan du langage D et pour moi plutôt que faire du mono il faudrait que la communauté se penche un peu plus sur ce langage. Il ne faut pas oublier que les contributeurs ne sont pas des newbie, par exemple A. Alexandrescu qui est une référence dans le monde du C++.
Maintenant tout n'est pas rose dans le D monde,par exemple le compilateur gdc est a la traine ce qui est un gros handicap.
[^] # Re: Intéressant pour les idées ... mais non
Posté par reno . Évalué à 4.
Dis plutôt que ce problème est en train d'être regler pour D2 (qui il me semble n'est pas encore sorti en version stable), mais que problème restera pour D1 ou la communauté des utilisateurs devant le manque de fonctionnalité de Phobos a realisé une autre 'librairie standard' incompatible techniquement et avec aussi une licence differente de celle de Phobos (une recherche google sur "SHOO's time library" montre bien le bazar résultant).
Ce qu'on peut résumer facilement en: un *gros* bordel, qui ne donne vraiment pas confiance dans la "plateforme D"..
Ce n'est donc *pas* un mauvais argument..
[^] # Re: Intéressant pour les idées ... mais non
Posté par Jonathan MERCIER (site web personnel) . Évalué à 1.
GDC est à jour et marche avec la D2
Phobos2 est stable
Tango2 n'a pas fini son portage D2
Le langage D me séduit bien plus que le Go, syntaxe, maintenant, performance ... que du plaisir
Note: GDC sera intégré en standard a partir de gcc 4.7
[^] # Re: Intéressant pour les idées ... mais non
Posté par reno . Évalué à 3.
Ahem, ça dépend de la définition de stable..
Ma définition de stable, c'est stable comme un compilateur C.
D2 en est loin..
La spec est stable, les implémentations .. non.
Au niveau de la syntaxe D est pas mal effectivement, dommage qu'il ait gardé la syntaxe de la déclaration de variable a la C, heureusement qu'il y a l'inférence de type..
> Note: GDC sera intégré en standard a partir de gcc 4.7
ça c'est une très bonne nouvelle!!
[^] # Re: Intéressant pour les idées ... mais non
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 5.
# Commentaire supprimé
Posté par Anonyme . Évalué à 10.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: Quel goplay ?
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 1.
[^] # Re: Quel go ?
Posté par boq . Évalué à 2.
En même temps si le succès de leur langage tiens à un changement de nom, ça va être facile :)
# Groland
Posté par Nucleos . Évalué à 1.
[^] # Re: Groland
Posté par rewind (Mastodon) . Évalué à 5.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.